接下來的測試將會需要用到 mocking 的 library ,在 Android 大家比較常用的是 MockK 和 Mockito 。這篇要介紹的是 MockK,它是一個專門支援 Kotlin 的 mocking library ,來看看它有哪些特點吧!
如果沒有寫測試經驗的朋友應該不太了解甚麼是 mocking ,我們可以用一個例子來了解一下。假如我們有個 ApiService
,它對外提供 User
實體給其他人,而 ApiService
又實作了 Service
這個介面。
data class User(val name: String, val id: Long)
interface Service {
fun getUser(): User
}
class ApiService : Service {
override fun getUser() = User("John", 1L)
}
有另一個類別 UserRepository
用到了 Service
介面來提供 User
。
class UserRepository(private val service: Service) {
fun getUser(): Flow<User> = flow {
if (user.id == -1) {
throw new InvalidUserIdException()
} else {
emit(service.getUser())
}
}
}
這時候,我們要針對 UserRepository
來寫測試的話,首先第一個要做的事情就是控制外部來的變數,也就是 Service
,因為他會控制我們 User 實體。如果我想要 UserRepository
丟出 InvalidUserIdException
錯誤的話,我可以透過一個假的 service
發出一個 id
為 -1 的假 User
來測試程式是不是會判斷 id
為 -1 。相反地,我們也可以測試正向的流程,也就是 id
不為 -1 的流程,這個就是 mocking 可以做的事情。
以上面這個例子如果使用 MockK 可以怎麼測?
@Test
fun `Test getting an user info by MockK`() = runBlocking {
val fakeUser = User("Doe", 2L)
val mockApiService = mockk<ApiService>(relaxed = true)
every { mockApiService.getUser() } returns fakeUser
val userRepository = UserRepository(mockApiService)
userRepository.getUser().collect {
assertEquals(it, fakeUser)
}
}
做一個 fakeUser
放到假的 ApiService
裡面,在 MockK 要做一個假的物件只要用 mockk<ApiService>
就可以了!下一行的 every...return
表示法就是指定當每次 mockApiService.getUser()
被呼叫的時候要回甚麼指定物件給呼叫的人,這邊我們指定 fakeUser
。另外,你可能也有發現 mockk<ApiService>
後面有個 relaxed = true
的參數,這個主要的是讓 mocking 的物件內的東西被呼叫的時候,有回給他一個基本值或是不作用,這個的好處是,假設今天我們的 ApiService
有 10 個方法,但我們只要操控 getUser
的結果,另外 9 個不管,我們只要對 getUser
做 every...return
塞值,另外 9 個不用一個個塞值。
另一個測試路線就是測試當 id 是 -1 的時候會不會丟 exception ,可以在測試方法前面寫上 @Test(expected = InvalidUserIdException::class)
,意思就是說我們期待這邊會丟出 InvalidUserIdException
。
@Test(expected = InvalidUserIdException::class)
fun `Test getting an user info by MockK`() = runBlocking {
val fakeUser = User("Doe", -1L)
val mockApiService = mockk<ApiService>(relaxed = true)
every { mockApiService.getUser() } returns fakeUser
val userRepository = UserRepository(mockApiService)
userRepository.getUser().collect()
}
MockK 在測試 Kotlin 程式碼的時候真的很好用,因為他的 API 是支援 Kotlin 的寫法,而且還有類似 DSL 的表達方式,讓我們在寫測試的時候可以很輕鬆地完成要寫的測試。如果你對於 MockK 有興趣的話,可以參考一下官網文件,他們的文件也是簡單易懂,讓測試可以簡單就上手。